package dreadnought;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * This represents a single cell of the grid
 * A grid contains 100 individual GridCell's
 */
public class GridCell extends JLabel
{
    private Game game;
    private Grid grid;
    private GridCoordinate anchor;
    private CellState state;

    public int heuristicValue;
    public int heuristicIndex;

    //whether or not this grid cell has been fired at
    //note that if hit==true that does not necessarily mean that
    //a ship was hit at this grid cell, it could be a miss.
    //hit just means whether or not this particular grid cell
    //has been fired upon or not
    private boolean hit;

    private ImageIcon explosionIcon;
    
    public GridCell(Game game, Grid grid, GridCoordinate anchor)
    {
        //this.setOpaque(true);
        //this.setBackground(Color.CYAN);
        this.game = game;
        this.grid = grid;
        this.anchor = anchor;
        
        //the state of a cell is unknown at first meaning it hasn't been hit
        this.state = CellState.UNKNOWN;

        //calcluate the bounding rectangle of this cell
        this.setBounds(new Rectangle(
                game.PAD + game.CELL * this.anchor.getCol(),
                game.PAD + game.CELL * this.anchor.getRow(),
                game.CELL + 1, game.CELL + 1));

        this.setBorder(BorderFactory.createLineBorder(Color.black));

        this.addMouseListener(new CellListener());

        //load explosion image
        this.explosionIcon = new ImageIcon(
                this.getClass().getResource("/dreadnought/explosion.png"));

        this.setHorizontalAlignment(JLabel.CENTER);
    }

    /**
     * returns the anchor coordinate of a GridCell object
     * @return the anchor coordinate of a GridCell
     */
    public GridCoordinate getAnchor()
    {
        return this.anchor;
    }

    /**
     * Returns the state of a GridCell, represented by one of the values
     * of the {@link CellState} enumeration.
     * @return the state of the cell
     */
    public CellState getState()
    {
        return this.state;
    }

    /**
     * paints the component
     * @param g the graphics context
     */
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
    }

    /**
     * Returns a reference to the GridCell instance.
     * Used by the private listener class to get a reference
     * to it's containing class.
     * @return a reference to this instance, same as this keyword
     */
    public GridCell getThis()
    {
        return this;
    }

    /**
     * This is called when a GridCell which is occuppied by a Ship is fired
     * upon. It will be called by the fire() method of the {@link PlayerGrid}
     * or {@link EnemyGrid} class.
     */
    public void markAsHit()
    {
        //change the state to hit
        this.state = CellState.HIT;
        //change the icon of this GridCell to explosionIcon
        this.setIcon(explosionIcon);
        //change the layer of this cell so that it is displayed
        //above any ships
        this.grid.setLayer(this, 2);
        this.repaint();
    }

    /**
     * This is called when a GridCell which is not occuppied by a Ship is fired
     * upon. It will be called by the fire() method of the {@link PlayerGrid}
     * or {@link EnemyGrid} class.
     */
    public void markAsMiss()
    {
        //change the state to miss
        this.state = CellState.MISS;
        //mark the cell with an "x" to show that it was a miss
        this.setForeground(Color.decode("#eeeeee"));
        this.setText("x");
        //change the layer of this cell so that it is displayed
        //above any ships
        this.grid.setLayer(this, 2);
        this.repaint();
    }

    /**
     * Returns the heuristic value of this GridCell as calculated by the
     * heuristic functions in the Grid class.
     * @return the heuristic value of a GridCell
     */
    public int updateHeuristic()
    {
        this.heuristicValue = this.grid.getHeuristic(this);
        return this.heuristicValue;
    }

    public void updateBackgroundFromHeuristic()
    {
       //TODO: update cell background color based on heuristic
       //if this is not the enemy's grid
       if (!this.grid.cellsClickable
               && this.state == CellState.UNKNOWN
               && game.SHOW_HEURISTIC_COLORS)
       {
           //get the heuristic value of this GridCell as a percentage
           float percent = this.heuristicValue / (float)this.grid.maxHeuristic;
           //percent = 1 - percent; //invert the colors
           percent *= 0.5; //make it more transparent
           Color bg = new Color(1.0f, 0, 0, percent);
           this.setOpaque(true);
           this.setBackground(bg);
       }
       else
       {
           this.setOpaque(false);
       }
       this.repaint();
    }
    
    /**
     * A private listener class which handles all events related to
     * a GridCell. The only currently implemented event is mouseClicked().
     */
    private class CellListener implements MouseListener
    {
        /**
         * Handles the user clicking on a GridCell.
         * Only GridCells which are part of the enemy grid should be clickable.
         * @param e the MouseEvent object
         */
        public void mouseClicked(MouseEvent e)
        {
            //only allow grid cell to be clicked if it is clickable
            //and it is currently the players turn
            if (grid.cellsClickable && game.getState() == GameState.PLAYER_TURN)
            {
                //left click fires at a ship
                if (e.getButton() == e.BUTTON1)
                    grid.fire(anchor);
            }
            //the following right click handler is just for testing purposes
            if (e.getButton() == e.BUTTON3)
            {
                String msg = "Coordinate: " + anchor + "\n"
                        + "heuristicValue: " + getThis().heuristicValue + "\n"
                        + "heurisitcIndex: " + heuristicIndex + "\n";
                game.alert(msg);
            }
        }


        public void mousePressed(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}
        public void mouseEntered(MouseEvent e) {}
        public void mouseReleased(MouseEvent e) {}
    }
}
